package cn.wolfcode.shop.filter;

import cn.wolfcode.shop.common.CodeMsg;
import cn.wolfcode.shop.common.Result;
import com.alibaba.fastjson.JSON;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import static com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.RateLimitConstants.RATE_LIMIT_EXCEEDED;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ERROR_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_ERROR_FILTER_ORDER;

/**
 * 自定义错误过滤器，在run方法中实现过滤逻辑，其他的都是拷贝源码
 */
@Component  // 交给Spring进行管理
@Slf4j
public class SeckillErrorFilter extends ZuulFilter {
    protected static final String SEND_ERROR_FILTER_RAN = "sendErrorFilter.ran";

    @Value("${error.path:/error}")
    private String errorPath;

    @Override
    public String filterType() {
        return ERROR_TYPE;
    }

    @Override
    public int filterOrder() {
        return SEND_ERROR_FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        // only forward to errorPath if it hasn't been forwarded to already
        return ctx.getThrowable() != null
                && !ctx.getBoolean(SEND_ERROR_FILTER_RAN, false);
    }

    // 自己实现错误过滤逻辑， 上面的三个方法和常量都是拷贝源码来的（几乎和SendErrorFilter一样）
    @Override
    public Object run() throws ZuulException {
        // 错误打印
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable throwable = ctx.getThrowable();
        HttpServletRequest request = ctx.getRequest();
        log.error("Error during filtering", throwable);

        // 1.创建一个默认的错误对象
        Result result = Result.defaultError();
        // 2.如果当前异常是 ratelimit 的异常，返回访问次数过多的错误提示
        Object rateLimitExceeded = ctx.get(RATE_LIMIT_EXCEEDED);
        if (Boolean.TRUE.toString().equals(rateLimitExceeded)) {
            result = Result.error(new CodeMsg(500429, "你访问的次数太多了，请稍后再试！"));
            ctx.setSendZuulResponse(false); //如果出错，之后的过滤链就不在执行了（效率高）
        }
        // 3.将错误结果响应回去
        HttpServletResponse response = ctx.getResponse();
        response.setContentType("application/json;charset=utf-8");
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException e) {
            log.error("响应网关错误结果异常！", e);
        }
        return null;
    }
}
